/**
 * 浏览器原生打印工具类
 * 使用 iframe 方式实现打印，不影响当前页面
 */

/**
 * 打印配置接口
 */
export interface PrintConfig {
  /** 打印内容(HTML字符串或DOM元素) */
  content: string | HTMLElement;
  /** 打印标题 */
  title?: string;
  /** 打印样式配置 */
  styles?: {
    /** 纸张大小:  A5, A6 等 */
    pageSize?: 'A5' | 'A80' | string;
    /** 纸张方向: portrait(纵向) 或 landscape(横向) */
    orientation?: 'portrait' | 'landscape';
    /** 页边距 */
    margin?: string;
    /** 自定义CSS样式 */
    customStyles?: string;
  };
  /** 打印前回调 */
  onBeforePrint?: () => void;
  /** 打印后回调 */
  onAfterPrint?: () => void;
  /** iframe移除延迟时间(ms)，默认500ms */
  removeDelay?: number;
}

/**
 * 常用纸张尺寸预设
 */
export const PAPER_SIZES = {
  /** A5 纸张: 148mm × 210mm */
  A5: { width: '148mm', height: '210mm', name: 'A5' },
  /** 80mm 热敏纸 */
  A80: { width: '80mm', height: 'auto', name: 'A80' },
} as const;

/**
 * 生成打印样式
 * @param config 打印配置
 * @returns CSS样式字符串
 */
const generatePrintStyles = (config: PrintConfig): string => {
  const {
    pageSize = 'A5',
    orientation = 'portrait',
    margin = '5mm',
    customStyles = '',
  } = config.styles || {};

  return `
    /* 基础样式 */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      margin: 0;
      padding: 0;
      font-family: 'Microsoft YaHei', sans-serif;
      -webkit-print-color-adjust: exact;
      print-color-adjust: exact;
    }

    /* 打印样式 */
    @media print {
      @page {
        size: ${pageSize} ${orientation};
        margin: ${margin};
      }

      html, body {
        margin: 0 !important;
        padding: 0 !important;
      }

      body {
        margin: 0;
        padding: 10mm !important;
      }

      /* 避免内容被分页截断 */
      h1, h2, h3, h4, h5, h6 {
        page-break-after: avoid;
        page-break-inside: avoid;
        break-after: avoid;
        break-inside: avoid;
      }

      table, figure, img {
        page-break-inside: avoid;
        break-inside: avoid;
      }

      tr {
        page-break-inside: avoid;
        break-inside: avoid;
      }

      /* 强制分页类 */
      .page-break,
      .print-page-break {
        page-break-after: always;
        break-after: page;
      }

      .page-break:last-child,
      .print-page-break:last-child {
        page-break-after: auto;
        break-after: auto;
      }

      /* 隐藏打印时不需要的元素 */
      .no-print {
        display: none !important;
      }
    }

    /* 自定义样式 */
    ${customStyles}
  `;
};

/**
 * 获取打印内容HTML
 * @param config 打印配置
 * @returns 内容HTML字符串
 */
const getPrintContent = (config: PrintConfig): string => {
  if (typeof config.content === 'string') {
    return config.content;
  } else if (config.content instanceof HTMLElement) {
    return config.content.innerHTML;
  }
  return '';
};

/**
 * 执行打印
 * @param config 打印配置
 * @returns Promise<是否成功打印>
 */
const executePrint = async (config: PrintConfig): Promise<boolean> => {
  if (typeof window === 'undefined') {
    console.error('打印功能仅在浏览器环境中可用');
    return false;
  }

  return new Promise((resolve) => {
    try {
      // 打印前回调
      if (config.onBeforePrint) {
        config.onBeforePrint();
      }

      // 创建隐藏的iframe
      const iframe = document.createElement('iframe');
      iframe.style.position = 'fixed';
      iframe.style.top = '-10000px';
      iframe.style.left = '-10000px';
      iframe.style.width = '0';
      iframe.style.height = '0';
      iframe.style.border = 'none';

      document.body.appendChild(iframe);

      // 获取iframe的document
      const iframeWindow = iframe.contentWindow;
      const iframeDoc = iframeWindow?.document;

      if (!iframeWindow || !iframeDoc) {
        console.error('无法访问iframe document');
        document.body.removeChild(iframe);
        resolve(false);
        return;
      }

      // 获取打印内容
      const contentHtml = getPrintContent(config);
      const styles = generatePrintStyles(config);
      const title = config.title || '打印文档';

      // 写入内容
      iframeDoc.open();
      iframeDoc.write(`
        <!DOCTYPE html>
        <html lang="zh-CN">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>${title}</title>
          <style>${styles}</style>
        </head>
        <body>${contentHtml}</body>
        </html>
      `);
      iframeDoc.close();

      // 等待内容加载完成后打印
      const onLoadHandler = () => {
        try {
          // 执行打印
          iframeWindow.focus();
          iframeWindow.print();

          // 打印后清理
          const removeDelay = config.removeDelay ?? 500;
          setTimeout(() => {
            try {
              if (iframe.parentNode) {
                document.body.removeChild(iframe);
              }

              // 打印后回调
              if (config.onAfterPrint) {
                config.onAfterPrint();
              }

              resolve(true);
            } catch (err) {
              console.error('移除iframe失败:', err);
              resolve(true);
            }
          }, removeDelay);
        } catch (err) {
          console.error('打印执行失败:', err);
          if (iframe.parentNode) {
            document.body.removeChild(iframe);
          }
          resolve(false);
        }
      };

      // 监听iframe加载完成
      if (iframeWindow.document.readyState === 'complete') {
        // 已经加载完成，直接执行
        setTimeout(onLoadHandler, 100);
      } else {
        // 等待加载完成
        iframe.onload = onLoadHandler;
      }
    } catch (err) {
      console.error('打印失败:', err);
      resolve(false);
    }
  });
};

/**
 * 打印预览（浏览器原生打印对话框即为预览）
 * @param config 打印配置
 * @returns Promise<是否成功调用打印>
 */
export const printPreview = async (config: PrintConfig): Promise<boolean> => {
  return await executePrint(config);
};

/**
 * 直接打印（与预览相同，浏览器会显示打印对话框）
 * @param config 打印配置
 * @returns Promise<是否成功调用打印>
 */
export const printDirect = async (config: PrintConfig): Promise<boolean> => {
  return await executePrint(config);
};

/**
 * 通用打印方法
 * @param config 打印配置
 * @param isPreview 是否预览（浏览器原生打印默认都会显示预览对话框）
 * @returns Promise<是否成功调用打印>
 */
export const printCommon = async (
  config: PrintConfig,
  isPreview: boolean = true
): Promise<boolean> => {
  return isPreview ? await printPreview(config) : await printDirect(config);
};

/**
 * 打印指定DOM元素
 * @param element DOM元素或元素选择器
 * @param options 打印选项
 * @returns Promise<是否成功打印>
 */
export const printElement = async (
  element: HTMLElement | string,
  options: Omit<PrintConfig, 'content'> = {}
): Promise<boolean> => {
  let targetElement: HTMLElement | null = null;

  if (typeof element === 'string') {
    targetElement = document.querySelector(element);
    if (!targetElement) {
      console.error(`未找到元素: ${element}`);
      return false;
    }
  } else {
    targetElement = element;
  }

  return await printCommon({
    ...options,
    content: targetElement,
  });
};

/**
 * 打印HTML字符串
 * @param html HTML字符串
 * @param options 打印选项
 * @returns Promise<是否成功打印>
 */
export const printHtml = async (
  html: string,
  options: Omit<PrintConfig, 'content'> = {}
): Promise<boolean> => {
  return await printCommon({
    ...options,
    content: html,
  });
};

/**
 * 批量打印配置接口
 */
export interface BatchPrintConfig {
  /** 打印配置数组 */
  printConfigs: PrintConfig[];
  /** 每次打印之间的延迟时间(ms)，默认1000ms */
  delayBetweenPrints?: number;
  /** 打印进度回调 */
  onProgress?: (current: number, total: number, config: PrintConfig) => void;
  /** 全部打印完成回调 */
  onComplete?: (successCount: number, failCount: number) => void;
  /** 打印失败时是否继续，默认true */
  continueOnError?: boolean;
}

/**
 * 批量打印结果接口
 */
export interface BatchPrintResult {
  /** 总数 */
  total: number;
  /** 成功数量 */
  successCount: number;
  /** 失败数量 */
  failCount: number;
  /** 详细结果 */
  results: Array<{
    index: number;
    success: boolean;
    config: PrintConfig;
    error?: any;
  }>;
}

/**
 * 批量打印多个内容（合并打印，只弹出一次对话框）
 * 将多个打印内容合并成一个文档，通过CSS分页控制，实现一次性打印多页
 *
 * @param batchConfig 批量打印配置
 * @returns Promise<批量打印结果>
 *
 * @example
 * ```typescript
 * // 批量打印挂号单和收费单（只弹出一次对话框）
 * const result = await printMultiple({
 *   printConfigs: [
 *     { content: html1, styles: { pageSize: 'A80' } },
 *     { content: html2, styles: { pageSize: 'A80' } },
 *     { content: html3, styles: { pageSize: 'A80' } },
 *   ],
 *   onComplete: (successCount, failCount) => {
 *     console.log(`打印完成：成功 ${successCount} 张，失败 ${failCount} 张`);
 *   }
 * });
 * ```
 */
export const printMultiple = async (
  batchConfig: BatchPrintConfig
): Promise<BatchPrintResult> => {
  const { printConfigs, onProgress, onComplete } = batchConfig;

  const results: BatchPrintResult['results'] = [];
  let successCount = 0;
  let failCount = 0;

  try {
    // 检查所有配置是否使用相同的打印样式
    const firstConfig = printConfigs[0];
    const hasSameStyles = printConfigs.every(
      (config) =>
        JSON.stringify(config.styles) === JSON.stringify(firstConfig?.styles)
    );

    if (!hasSameStyles) {
      console.warn('打印配置的样式不一致，将使用第一个配置的样式进行合并打印');
    }

    // 提取所有HTML内容
    const htmlArray: string[] = printConfigs.map((config) => {
      if (typeof config.content === 'string') {
        return config.content;
      } else if (config.content instanceof HTMLElement) {
        return config.content.innerHTML;
      }
      return '';
    });

    // 触发进度回调（合并打印只触发一次）
    if (onProgress) {
      onProgress(1, 1, firstConfig!);
    }

    // 使用合并打印方式（只弹出一次对话框）
    const success = await printMergedPages({
      htmlArray,
      options: {
        title: firstConfig?.title || '打印文档',
        styles: firstConfig?.styles,
        onBeforePrint: firstConfig?.onBeforePrint,
        onAfterPrint: firstConfig?.onAfterPrint,
        removeDelay: firstConfig?.removeDelay,
      },
      autoAddPageBreak: true,
    });

    if (success) {
      // 所有打印内容都成功
      successCount = printConfigs.length;
      printConfigs.forEach((config, index) => {
        results.push({
          index,
          success: true,
          config: config!,
        });
      });
    } else {
      // 打印失败
      failCount = printConfigs.length;
      printConfigs.forEach((config, index) => {
        results.push({
          index,
          success: false,
          config: config!,
          error: '打印失败',
        });
      });
    }
  } catch (error) {
    console.error('批量打印失败:', error);
    failCount = printConfigs.length;
    printConfigs.forEach((config, index) => {
      results.push({
        index,
        success: false,
        config: config!,
        error,
      });
    });
  }

  // 触发完成回调
  if (onComplete) {
    onComplete(successCount, failCount);
  }

  return {
    total: printConfigs.length,
    successCount,
    failCount,
    results,
  };
};

/**
 * 批量打印HTML字符串数组（依次弹出多个打印对话框）
 *
 * @param htmlArray HTML字符串数组
 * @param commonOptions 通用打印选项
 * @param batchOptions 批量打印选项
 * @returns Promise<批量打印结果>
 *
 * @example
 * ```typescript
 * const result = await printHtmlArray(
 *   [html1, html2, html3],
 *   { styles: { pageSize: 'A80', margin: '0mm' } },
 *   {
 *     delayBetweenPrints: 1500,
 *     onProgress: (current, total) => {
 *       console.log(`正在打印第 ${current}/${total} 张`);
 *     }
 *   }
 * );
 * ```
 */
export const printHtmlArray = async (
  htmlArray: string[],
  commonOptions: Omit<PrintConfig, 'content'> = {},
  batchOptions: Omit<BatchPrintConfig, 'printConfigs'> = {}
): Promise<BatchPrintResult> => {
  const printConfigs: PrintConfig[] = htmlArray.map((html) => ({
    ...commonOptions,
    content: html,
  }));

  return await printMultiple({
    ...batchOptions,
    printConfigs,
  });
};

/**
 * 合并打印配置接口
 */
export interface MergedPrintConfig {
  /** HTML内容数组 */
  htmlArray: string[];
  /** 通用打印选项 */
  options?: Omit<PrintConfig, 'content'>;
  /** 每页内容的包裹类名，默认为 'print-page-break' */
  pageWrapperClass?: string;
  /** 是否自动添加分页样式，默认为 true */
  autoAddPageBreak?: boolean;
}

/**
 * 合并打印多个HTML内容（只弹出一次打印对话框）
 * 将多个HTML内容合并成一个文档，通过CSS分页控制，实现一次性打印多页
 *
 * @param config 合并打印配置
 * @returns Promise<是否成功打印>
 *
 * @example
 * ```typescript
 * // 一次性打印多张处方单（只弹出一次对话框）
 * const success = await printMergedPages({
 *   htmlArray: [prescription1Html, prescription2Html, prescription3Html],
 *   options: {
 *     title: '处方笺',
 *     styles: {
 *       pageSize: 'A5',
 *       orientation: 'portrait',
 *       margin: '10mm',
 *     }
 *   },
 *   autoAddPageBreak: true,
 * });
 * ```
 */
export const printMergedPages = async (
  config: MergedPrintConfig
): Promise<boolean> => {
  const {
    htmlArray,
    options = {},
    pageWrapperClass = 'print-page-break',
    autoAddPageBreak = true,
  } = config;

  if (!htmlArray || htmlArray.length === 0) {
    console.error('HTML内容数组不能为空');
    return false;
  }

  // 合并所有HTML内容，每个内容用div包裹并添加分页类
  // 包裹器只负责分页，不添加任何可能影响布局的样式
  const mergedHtml = htmlArray
    .map((html, index) => {
      const isLast = index === htmlArray.length - 1;
      const breakClass = autoAddPageBreak && !isLast ? pageWrapperClass : '';
      return `<div class="${breakClass}">${html}</div>`;
    })
    .join('\n');

  // 执行打印
  return await printHtml(mergedHtml, options);
};

/**
 * 合并打印DOM元素数组（只弹出一次打印对话框）
 *
 * @param elements DOM元素数组或选择器数组
 * @param config 合并打印配置
 * @returns Promise<是否成功打印>
 *
 * @example
 * ```typescript
 * // 打印页面上的多个处方元素
 * const success = await printMergedElements(
 *   ['#prescription-1', '#prescription-2', '#prescription-3'],
 *   {
 *     options: {
 *       title: '处方笺',
 *       styles: { pageSize: 'A5', margin: '10mm' }
 *     }
 *   }
 * );
 * ```
 */
export const printMergedElements = async (
  elements: (HTMLElement | string)[],
  config: Omit<MergedPrintConfig, 'htmlArray'> = {}
): Promise<boolean> => {
  const htmlArray: string[] = [];

  for (const element of elements) {
    let targetElement: HTMLElement | null = null;

    if (typeof element === 'string') {
      targetElement = document.querySelector(element);
      if (!targetElement) {
        console.error(`未找到元素: ${element}`);
        continue;
      }
    } else {
      targetElement = element;
    }

    htmlArray.push(targetElement.innerHTML);
  }

  if (htmlArray.length === 0) {
    console.error('没有找到任何可打印的元素');
    return false;
  }

  return await printMergedPages({
    ...config,
    htmlArray,
  });
};
